package com.jnevision.leave.controller;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.api.ApiController;
import com.baomidou.mybatisplus.extension.api.R;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.crtland.landoss.LandOss;
import com.crtland.landoss.Oss;
import com.crtland.landoss.OssInfo;
import com.crtland.landoss.OssType;
import com.crtland.landoss.PathEnum;
import com.crtland.landoss.Result;
import com.jnevision.attendancegroup.model.AttendanceGroup;
import com.jnevision.attendancegroup.service.AttendanceGroupServiceImpl;
import com.jnevision.clockin.model.ClockIn;
import com.jnevision.clockin.service.ClockInServiceImpl;
import com.jnevision.common.CommonQuery;
import com.jnevision.leave.model.Leave;
import com.jnevision.leave.model.LeaveVO;
import com.jnevision.leave.service.LeaveServiceImpl;
import com.jnevision.leaveapprovalrecords.model.LeaveApprovalRecords;
import com.jnevision.leaveapprovalrecords.service.LeaveApprovalRecordsServiceImpl;
import com.jnevision.overtime.service.OvertimeServiceImpl;
import com.jnevision.user.model.User;
import com.jnevision.user.service.UserServiceImpl;
import com.jnevision.util.Base64Util;
import com.jnevision.util.DateUtil;
import com.jnevision.util.JsonMapper;

/**
 * <p>
 * 请假 前端控制器
 * </p>
 *
 * @author gavin
 * @since 2019-07-13
 */

@RestController
@RequestMapping("/leaves")
public class LeaveController extends ApiController {
    @Autowired
    private LeaveServiceImpl leaveServiceImpl;
    @Autowired
    private LeaveApprovalRecordsServiceImpl approvalRecordsServiceImpl;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private UserServiceImpl userServiceImpl;
    @Autowired
    private OssInfo ossInfo;
    @Autowired
    private ClockInServiceImpl clockInServiceImpl;
    @Autowired
    private AttendanceGroupServiceImpl attendanceGroupServiceImpl;
    @Autowired
    private OvertimeServiceImpl overtimeServiceImpl;

    /**
     * 请假提交
     * 
     * @param leave
     * @return
     */
    @PostMapping
    @Transactional
    public R<Boolean> add(@RequestBody Leave leave, @RequestHeader(value = "token") String token) {
        User user = JsonMapper.nonDefaultMapper().fromJson(this.redisTemplate.boundValueOps(token).get(), User.class);
        if (user == null) {
            return this.failed("请登录后提交请假信息");
        }

        if (leave.getTypeId() == 6
            && Float.parseFloat(leave.getDuration()) - this.overtimeServiceImpl.getRestTime(leave.getUserId()) > 0) {
            return this.failed("没有剩余的调休了，请选择其他选项");
        }

        // 上传假条
        if (StringUtils.isNotBlank(leave.getPicture())) {
            LandOss landOss = new LandOss(redisTemplate);
            Oss oss = landOss.getLandOss(OssType.ALI, ossInfo);

            MultipartFile file = Base64Util.base64ToMultipart(leave.getPicture());
            try {
                Result result = oss.upload(PathEnum.MATERIAL, file);
                leave.setPicture(result.getFileUrl());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        this.leaveServiceImpl.save(leave);
        LeaveApprovalRecords lar = new LeaveApprovalRecords();

        lar.setLeaveId(leave.getId());
        // 审批人
        // 如果相等说明是本人请假，否则为代请假
        if (StringUtils.equals(user.getId(), leave.getUserId())) {
            // 查找部门主管 让用户自己选择审批人，如果出现同一个部门两个相同角色的主管，系统无法判断
            String parentUserId = this.userServiceImpl.getParentUser(user.getId()).getId();
            lar.setUserId(parentUserId);
            lar.setResult(0); // 审核中
        } else {
            lar.setUserId(user.getId());
            lar.setResult(1); // 通过
            lar.setApproveTime(DateUtil.getNormalTime());
        }

        AttendanceGroup ag =
            this.attendanceGroupServiceImpl.getOne(new QueryWrapper<AttendanceGroup>().eq("dept_id", user.getDeptId()));

        if (ag == null) {
            return this.success(this.approvalRecordsServiceImpl.save(lar));
        }
        // 计算是否由项目经理审批
        int monMin = LocalTime.parse(ag.getMorningEnd() + ":00").toSecondOfDay()
            - LocalTime.parse(ag.getMorningStart() + ":00").toSecondOfDay();
        int afterMin = LocalTime.parse(ag.getAfternoonEnd() + ":00").toSecondOfDay()
            - LocalTime.parse(ag.getAfternoonStart() + ":00").toSecondOfDay();

        BigDecimal day = new BigDecimal(monMin + afterMin).divide(new BigDecimal(3600), RoundingMode.HALF_UP)
            .multiply(new BigDecimal(ag.getLeaveDuration())).setScale(1, RoundingMode.HALF_UP);

        if (Float.parseFloat(leave.getDuration()) > day.floatValue()) {
            String projectManagerId = this.userServiceImpl.getProjectManagerByCurrentUser(token);

            lar.setUserId(projectManagerId);
        }
        // 插入审批记录的基本信息，待审核后，更新审批记录

        return this.success(this.approvalRecordsServiceImpl.save(lar));
    }

    /**
     * 请假审批 <br>
     * 暂时放到这里吧
     * 
     * @param lar
     */
    @GetMapping
    public R<Boolean> update(LeaveApprovalRecords lar) {
        if (lar.getResult().equals(1) || lar.getResult().equals(4) || lar.getResult().equals(5)) {
            // 更新打卡信息
            String leaveId = this.approvalRecordsServiceImpl.getById(lar.getId()).getLeaveId();
            Leave leave = this.leaveServiceImpl.getById(leaveId);

            if (LocalDateTime.now()
                .isAfter(LocalDateTime.parse(leave.getStart(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))) {

                // 查找出请假区间的打卡记录，然后更新打卡记录
                List<ClockIn> clockIns = this.clockInServiceImpl.list(new QueryWrapper<ClockIn>()
                    .eq("user_id", leave.getUserId()).ge("work_day", leave.getStart()).le("work_day", leave.getEnd()));

                for (ClockIn clockIn : clockIns) {
                    // TODO 根据请假申请更新打卡时间记录
                    clockIn.setClockInStatus(2);
                    this.clockInServiceImpl.updateById(clockIn);
                }
            }
        }

        lar.setApproveTime(DateUtil.getNormalTime());
        return this.success(this.approvalRecordsServiceImpl.updateById(lar));
    }

    @GetMapping("/list/{ids}")
    public R<Boolean> updateList(@PathVariable String[] ids) {

        Collection<LeaveApprovalRecords> listByIds = this.approvalRecordsServiceImpl.listByIds(Arrays.asList(ids));
        listByIds.forEach(oar -> {
            oar.setReason("正常");
            oar.setResult(1);
            oar.setApproveTime(DateUtil.getNormalTime());

            // 更新打卡信息
            String leaveId = this.approvalRecordsServiceImpl.getById(oar.getId()).getLeaveId();
            Leave leave = this.leaveServiceImpl.getById(leaveId);

            if (LocalDateTime.now()
                .isAfter(LocalDateTime.parse(leave.getStart(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))) {

                // 查找出请假区间的打卡记录，然后更新打卡记录
                List<ClockIn> clockIns = this.clockInServiceImpl.list(new QueryWrapper<ClockIn>()
                    .eq("user_id", leave.getUserId()).ge("work_day", leave.getStart()).le("work_day", leave.getEnd()));

                for (ClockIn clockIn : clockIns) {
                    // TODO 根据请假申请更新打卡时间记录
                    clockIn.setClockInStatus(2);
                    this.clockInServiceImpl.updateById(clockIn);
                }
            }
        });

        return this.success(this.approvalRecordsServiceImpl.updateBatchById(listByIds));
    }

    /**
     * 请假审批记录
     */
    @GetMapping("/approve")
    public R<List<LeaveVO>> approve(@RequestHeader(value = "token") String token) {
        User user = JsonMapper.nonDefaultMapper().fromJson(this.redisTemplate.boundValueOps(token).get(), User.class);

        return this.success(this.leaveServiceImpl.getApprove(user.getId()));
    }

    /**
     * 请假审批详情
     * 
     * @param leaveRecordId
     * @return
     */
    @GetMapping("/detail")
    public R<LeaveVO> approveDetail(String leaveRecordId) {
        return this.success(this.leaveServiceImpl.getApproveDetail(leaveRecordId));
    }

    /**
     * 请假审批列表
     * 
     * @param page
     * @param commonQuery
     * @param result 状态1通过，2未通过，0审核中
     * @return
     */
    @GetMapping("/page")
    public R<IPage<LeaveVO>> page(Page<LeaveVO> page, CommonQuery commonQuery, Integer result,
        @RequestHeader("token") String token) {
        String userId = this.userServiceImpl.getLoginUser(token).getId();
        commonQuery.setUserId(userId);
        return this.leaveServiceImpl.page(page, commonQuery, result);
    }

    /**
     * 我的请假记录
     * 
     * @param page
     * @param token
     * @return
     */
    @GetMapping("/my")
    public R<IPage<LeaveVO>> myLeaves(Page<LeaveVO> page, @RequestHeader("token") String token) {
        String userId = this.userServiceImpl.getLoginUser(token).getId();

        return this.success(this.leaveServiceImpl.myLeaves(page, userId));
    }

    @DeleteMapping
    @Transactional
    public R<Boolean> delete(String id) {
        LeaveApprovalRecords lar = this.approvalRecordsServiceImpl.getById(id);

        this.approvalRecordsServiceImpl.removeById(id);

        return this.success(this.leaveServiceImpl.removeById(lar.getLeaveId()));
    }
}
